package jdk.jdk8.stream;

import cn.hutool.core.util.RandomUtil;
import jdk.jdk8.optional.User;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 2、中间操作
 * 无状态（Stateless）操作：指元素的处理不受之前元素的影响（unordered、filter、map、peek）；
 * 有状态（Stateful）操作：指该操作只有拿到所有元素之后才能继续下去（distinct、sorted、limit、skip）。
 *
 * @author guodd
 * @version 1.0
 * @since 1.8
 */
public class StreamMain02 {
    public static List<User> createUser() {
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("user" + i);
            user.setAge(i);

            users.add(user);
            List<Map<String, Object>> maps = new ArrayList<>();
            for (int j = 0; j < 4; j++) {
                HashMap<String, Object> map1 = new HashMap<>();
                map1.put(RandomUtil.randomNumbers(5), 12);
                maps.add(map1);
            }
            user.setMaps(maps);
        }
        return users;
    }

    // ==== 筛选与切片，filter、distinct、limit、skip
    @Test
    public void opt01() {
        List<User> users = createUser();
        System.out.println("==========filter过滤==========");
        // filter(Predicate p)接收lambda表达式，从流中过滤某些元素。
        // filter筛选，是按照一定的规则校验流中的元素，将符合条件的元素提取到新的流中的操作。
        users.stream().filter(e -> e.getName().contains("2")).forEach(System.out::println);

        System.out.println("==========limit是截断流==========");
        // limit是阶段流，使其元素不超过给定的数量。
        users.stream().filter(e -> !e.getName().contains("2")).limit(3).forEach(System.out::println);

        System.out.println("==========skip跳过元素==========");
        // skip跳过前三个元素
        users.stream().filter(e -> !e.getName().contains("2")).skip(3).forEach(System.out::println);

        System.out.println("==========distinct去重元素==========");
        // distinct筛选，通过流所产生元素的hashCode()和equals()去除重复数据。
        users.stream().distinct().forEach(System.out::println);
    }

    // 分页操作：skip、limit
    @Test
    public void skipPage() {
        List<User> areaVo = StreamMain02.createUser().stream()
                // 2 10 (2-1)*10
                // (pageable.getPageNumber() - 1) * pageable.getPageSize()
                .skip(5)
                // pageable.getPageSize()
                .limit(10)
                .collect(Collectors.toList());
        System.out.println(areaVo);
    }

    // map映射，将集合中的元素A转换成想要得到的B
    @Test
    public void mapData() {
        // map映射，接收一个函数作为参数，将元素转换成其他形式或提取信息
        System.out.println("==========map映射==========");
        List<String> strings = Arrays.asList("java", "c", "c++");
        strings.stream().map(String::toUpperCase).forEach(System.out::println);
        System.out.println("-----------------");

        // 名字大于三的人
        List<String> collect = createUser().stream()
                .map(User::getName)
                .filter(name -> name.length() > 3)
                .collect(Collectors.toList());
        System.out.println(collect);
        System.out.println("-----------------");

        createUser().stream().map(User::getName).filter(e -> e.length() > 6).forEach(System.out::println);
    }

    // 类比：add()、addAll();
    // flatMap映射，接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有所有的流串起来。
    // 与Map功能类似，区别在于将结合A的流转换成B流
    // map和flatMap的特例版：mapToInt、mapToLong、mapToDouble、flatMapToDouble、flatMapToInt、flatMapToLong
    @Test
    public void flatMap() {
        List<String> strings = Arrays.asList("java", "c", "javascript");
        // stream嵌套
        Stream<Stream<Character>> streamStream = strings.stream().map(StreamMain02::charUp);
        streamStream.forEach(e -> e.forEach(System.out::print));

        System.out.println();
        Stream<Character> characterStream = strings.stream().flatMap(StreamMain02::charUp);
        characterStream.forEach(System.out::print);
    }

    public static Stream<Character> charUp(String str) {
        ArrayList<Character> characters = new ArrayList<>();
        for (Character s : str.toCharArray()) {
            characters.add(s);
        }
        return characters.stream();
    }

    // 排序，sort
    // 自然排序-sorted
    // 定制排序-sorted(comparator com)
    @Test
    public void listSort01() {
        // comparable接口
        List<Integer> integers = Arrays.asList(2, 1, 4, 67, 3, 1, 7, 78, 0);
        integers.stream().sorted().forEach(System.out::println);
        System.out.println();
        // comparator临时比较
        integers.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
        integers.stream().sorted(Comparator.comparing(Integer::intValue).reversed()).forEach(System.out::println);
        System.out.println("---");
        createUser().stream().sorted(Comparator.comparing(User::getAge)).forEach(System.out::println);
        List<User> collect = createUser().stream()
                .sorted(Comparator.comparing(User::getAge).reversed())  // reversed排序倒序
                .collect(Collectors.toList());  // 转List
        System.out.println(collect);
    }

    // 排序字段有空的情况
    @Test
    public void listSort02() {
        List<User> users = createUser();
        // 添加空的排序会报错
        users.add(new User());
        List<User> collect = users.stream()
                // 查找stream.sorted源码看到有Comparator.nullsFirst和Comparator.nullsLast方法
                .sorted(Comparator.comparing(User::getAge, Comparator.nullsFirst(Integer::compareTo)).reversed())
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    // 匹配
    @Test
    public void match() {
        // allMatch()检查是否匹配所有元素
        System.out.println("allMatch()检查是否匹配所有元素");
        boolean allMatch = StreamMain02.createUser().stream().allMatch(e -> e.getAge() > 5);
        System.out.println(allMatch);
        // anyMatch()检查是否至少匹配一个元素，短路-anyMatch
        System.out.println("anyMatch()检查是否至少匹配一个元素");
        boolean anyMatch = StreamMain02.createUser().stream().anyMatch(e -> e.getAge() > 5);
        System.out.println(anyMatch);
        // noneMatch()检查是否没有匹配的元素
        System.out.println("noneMatch()检查是否没有匹配的元素，即没有姓郭的");
        boolean noneMatch = StreamMain02.createUser().stream().noneMatch(e -> e.getName().startsWith("郭"));
        System.out.println(noneMatch);
    }

    // 查找
    @Test
    public void find() {
        // 用户信息输出
        StreamMain02.createUser().forEach(System.out::println);
        // findFirst()返回第一个元素
        System.out.println("findFirst()返回第一个元素");
        Optional<User> first = StreamMain02.createUser().stream().findFirst();
        System.out.println(first.map(User::getName));
        // findAny()返回任意一个元素
        System.out.println("findAny()返回任意一个元素");
        System.out.println(StreamMain02.createUser().stream().findAny());
        System.out.println(StreamMain02.createUser().parallelStream().findAny());
        // count返回元素总数
        System.out.println("count返回元素总数");
        System.out.println(StreamMain02.createUser().stream().filter(e -> e.getAge() > 5).count());
        // max返回最大值，Comparator.naturalOrder比较器以自然顺序比较
        System.out.println("max返回最大值");
        System.out.println(StreamMain02.createUser().stream().map(User::getAge).max(Comparator.naturalOrder()));
        // min返回最小值
        System.out.println("min返回最小值");
        System.out.println(StreamMain02.createUser().stream().map(User::getAge).min(Comparator.naturalOrder()));
        // forEach内部迭代
        System.out.println("forEach内部迭代");
        StreamMain02.createUser().stream().map(User::getAge).forEach(System.out::print);
    }
}
